package com.cy.pj.common.aspect;
import java.lang.reflect.Method;
import java.util.Date;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.jboss.logging.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.cy.pj.common.annotation.RequiredLog;
import com.cy.pj.common.util.IPUtils;
import com.cy.pj.common.util.ShiroUtils;
import com.cy.pj.sys.dao.SysLogDao;
import com.cy.pj.sys.entity.SysLog;
import com.cy.pj.sys.service.SysLogService;
import com.fasterxml.jackson.databind.ObjectMapper;

import lombok.extern.slf4j.Slf4j;
@Aspect
@Component
@Slf4j
public class SysLogAspect {

	private Logger log = Logger.getLogger(SysLogAspect.class);

	@Autowired
	private SysLogDao sysLogDao;

	@Pointcut("@annotation(com.cy.pj.common.annotation.RequiredLog)")
	public void logPointCut() {}



	//切入点 为一种切入点表达式
	//@Pointcut用于定义切入点 就是bean的一个名字 
	//	@Pointcut("bean(sysUserServiceImpl)")
	//后缀为ServiceImpl所有
	//	@Pointcut("bean(*ServiceImpl)")


	/**
	 *	环绕通知
	 *		可以在目标方法之前或者之后添加自己的拓展业务
	 *		方法返回值类型一般写Object
	 *		方法参数类型为 ProceedingJoinPoint 封装了目标方法信息
	 *		方法异常抛出为Throwable类型
	 * @param jp
	 * @return
	 * @throws Throwable
	 */
	@Around("logPointCut()")
	public Object around(ProceedingJoinPoint jp) throws Throwable {
		//1.记录目标方法开始执行时间
		long t1=System.currentTimeMillis();
		log.info("start time:"+t1);
		//2.执行目标方法
		Object result=jp.proceed();//假如有下一个切面先执行切面对象方法
		//3.记录目标方法结束执行时间
		long t2=System.currentTimeMillis();
		log.info("end time:"+t2);
		//记录用户行为日志
		saveLog(jp,(t2-t1));
		return result;
	}
	@Autowired
	private SysLogService logService;

	//获取用户行为日志信息,然后将日志写入到数据库
	private void saveLog(ProceedingJoinPoint joinPoint,long time)throws Exception {
		//1.获取日志信息
		//获取目标方法对象
		Method targetMethod = getTargetMethod(joinPoint);
		//获取目标方法名:目标类全名+方法名
		String classMethodName=getTargetMethodName(targetMethod);
		//获取操作名
		String operation= getOperation(targetMethod);
		//String params=Arrays.toString(joinPoint.getArgs());
		//获取方法执行时的实际参数
		String params=
				new ObjectMapper().writeValueAsString(joinPoint.getArgs());
		//2.封装日志信息
		SysLog sysLog=new SysLog(null,
				ShiroUtils.getUsername(),//登录用户名
				operation,
				classMethodName,
				params,
				time,
				IPUtils.getIpAddr(),
				new Date());
		//3.持久化日志信息
		logService.saveObject(sysLog);
	}

	private String getOperation(Method targetMethod) {
		RequiredLog rLog=
				targetMethod.getAnnotation(RequiredLog.class);
		return rLog.value();
	}

	private String getTargetMethodName(Method targetMethod) {
		return targetMethod.getDeclaringClass().getName()
				+"."+targetMethod.getName();
	}

	private Method getTargetMethod(ProceedingJoinPoint joinPoint) throws NoSuchMethodException {
		Class<?> targetClass=joinPoint.getTarget().getClass();
		MethodSignature s=(MethodSignature)joinPoint.getSignature();//方法签名
		Method targetMethod=
				targetClass.getMethod(
						s.getName(),
						s.getParameterTypes());
		return targetMethod;
	}
}







